package com.tx.admin.util.common;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.Collection;

import javax.persistence.Entity;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaBuilder.In;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.apache.commons.lang3.StringUtils;
import org.springframework.core.annotation.AnnotationUtils;

import com.tx.admin.core.anno.JpaKey;

public class JpaUtil {


		public static Predicate buildSql(Object obj,Root<?> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
			if(obj == null) {
				return null;
			}
	
			Predicate predicate = null;
			Predicate userPredicate = null;
			Predicate sysPredicate = null;

			Class clazz = obj.getClass();
	
			for(Field field:ReflectionUtils.getAllDeclaredFields(clazz)) {
				if(Modifier.isStatic( field.getModifiers())) {
					continue;
				}
				predicate = null;
				String key = field.getName();
			
				String operate="=";
				Object val = ReflectionUtils.invokeGetter(obj, key);
				if(val == null) {
					continue;
				}
		
				JpaKey jpaKey = field.getAnnotation(JpaKey.class);
				boolean and = true,sys=false;
				if(jpaKey != null) {
					if(StringUtils.isNotBlank(jpaKey.key())) {
						key = jpaKey.key();
					}
					if(StringUtils.isNotBlank(jpaKey.value())) {
						operate = jpaKey.value();
					}
					and = jpaKey.and();
					sys=jpaKey.sys();
			
				}
				
				if(val instanceof Comparable) {
					Comparable<Object> comparable =(Comparable) val ;
					
					switch (operate) {
					case "=":
						predicate = cb.equal(root.get(key), val);
						break;
					case "<=":
						predicate = cb.lessThanOrEqualTo(root.get(key),comparable);
							break;
					case ">=":
						predicate = cb.greaterThanOrEqualTo(root.get(key),comparable);			
						break;
					case "<":
						predicate = cb.lessThan(root.get(key),comparable);
						break;
					case ">":
						predicate = cb.greaterThan(root.get(key),comparable);
					case "like":
						predicate = cb.like(root.get(key), "%"+comparable+"%");
						break;
					default :
						predicate = cb.equal(root.get(key), val);
						break;
					}
				}else if(val instanceof Collection){
			
						In<Object> in=cb.in(root.get(key));	
						Collection<?> iterate=(Collection<?>) val;
						if(iterate.size() == 0) {
							continue;
						}
						for(Object v:iterate) {
							in.value(v);
						}
						predicate = in;
					
				}else {
				
					Entity entity = AnnotationUtils.findAnnotation(val.getClass(), Entity.class);
		
					if(entity != null) {
						predicate = buildSql(val, query.from(val.getClass()), query, cb);
					}else {
						predicate = cb.equal(root.get(key), val);
						
					}
					
				}
				
	
				if(and) {
					if(sys) {
						if(sysPredicate == null) {
							sysPredicate = predicate;
						}else {
							sysPredicate = cb.and(sysPredicate,predicate);
						}
					}else {
						if(userPredicate == null) {
							userPredicate = predicate;
						}else {
							userPredicate = cb.and(userPredicate,predicate);
						}
						
					}
				}else {
					if(sys) {
						if(sysPredicate == null) {
							sysPredicate = predicate;
						}else {
							sysPredicate = cb.or(sysPredicate,predicate);
						}
					}else {
						if(userPredicate == null) {
							userPredicate = predicate;
						}else {
							userPredicate = cb.or(userPredicate,predicate);
						}
					}
				}
	
			}

			predicate = null;
			for(Predicate p:Arrays.asList(userPredicate,sysPredicate)) {
				if(p == null) {
					continue;
				}
		
				if(predicate == null) {
					predicate=p;
				}else {
					predicate=cb.and(predicate,p);
				}
			}
	
			return predicate;
		}

}
